package redisDB

import (
	"bytes"
	"strconv"
	"strings"
	"sync"

	"github.com/go-redis/redis"
)

var (
	mapClient = make(map[string]redis.Cmdable,20)// 连接全局对象
	lock sync.Mutex // 连接锁定防止并发访问
)

func GetRediClient(config map[string]string) (redis.Cmdable, error) {
	var key bytes.Buffer
	key.WriteString(config["ipport"])
	key.WriteString("#")
	key.WriteString(config["dbname"])
	keyConn := key.String()
	client, ok := mapClient[keyConn]
	if ok {
		return client, nil
	}
	lock.Lock()
	defer lock.Unlock()
	/*二次获取防止并发多次连接*/
	client, ok = mapClient[keyConn]
	if ok {
		return client, nil
	}
	newClient, err := connect(config)
	if err != nil {
		return nil, err
	}
	mapClient[keyConn] = newClient
	return newClient, nil
}


//获取客户端
func connect(config map[string]string) (redis.Cmdable, error) {
	addr, ok := config["ipport"]
	if !ok {
		addr = "127.0.0.1:27017"
	}
	password, ok := config["password"]
	if !ok {
		password = ""
	}
	dbStr, ok := config["dbname"]
	if !ok {
		dbStr = "0"
	}
	dbname, err := strconv.Atoi(dbStr)
	poolSize := 200
	poolSizeStr, ok := config["poolSize"]
	if ok {
		atoi, err := strconv.Atoi(poolSizeStr)
		if err == nil {
			poolSize = atoi
		}
	}
	mode := config["mode"]
	var rdb redis.Cmdable
	switch mode {
	case "Failover":
		//连接Redis哨兵模式
		rdb = redis.NewFailoverClient(&redis.FailoverOptions{
			MasterName:    "master",
			SentinelAddrs: strings.Split(addr,","),
			Password: password,
			PoolSize: poolSize,  // 连接池最大socket连接数，默认为4倍CPU数， 4 * runtime.NumCPU
			MinIdleConns: 10,//在启动阶段创建指定数量的Idle连接，并长期维持idle状态的连接数不少于指定数量；
		})
		break
	case "Cluster":
		//连接Redis集群模式
		rdb = redis.NewClusterClient(&redis.ClusterOptions{
			Addrs: strings.Split(addr,","),
			Password: password,
			PoolSize: poolSize,    // 连接池最大socket连接数，默认为4倍CPU数， 4 * runtime.NumCPU
			MinIdleConns: 10,//在启动阶段创建指定数量的Idle连接，并长期维持idle状态的连接数不少于指定数量；
		})
		break
	default:
		// 普通单机模式连接
		rdb = redis.NewClient(&redis.Options{
			Addr:     addr,
			Password: password,       // no password set
			DB:       dbname, 		  // use default DB
			//连接池容量及闲置连接数量
			PoolSize:     poolSize, 		  // 连接池最大socket连接数，默认为4倍CPU数， 4 * runtime.NumCPU
			MinIdleConns: 10, 		  //在启动阶段创建指定数量的Idle连接，并长期维持idle状态的连接数不少于指定数量；
		})
		break
	}
	_, err = rdb.Ping().Result()
	if err != nil {
		return nil, err
	}
	return rdb, nil
}

// 初始化连接(连接Redis哨兵模式)
func initClientSentry() (err error) {
	rdb := redis.NewFailoverClient(&redis.FailoverOptions{
		MasterName:    "master",
		SentinelAddrs: []string{"x.x.x.x:26379", "xx.xx.xx.xx:26379", "xxx.xxx.xxx.xxx:26379"},
	})
	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}

// 初始化连接(连接Redis集群模式)
func initClientCluster() (err error) {
	rdb := redis.NewClusterClient(&redis.ClusterOptions{
		Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},
	})
	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}
